#include <stdx/all.h>

class UpdateApplication : public Application
{
	class FileItem
	{
	public:
		string path;
		time_t utime;
		time_t mtime;
		set<string> incset;

		FileItem()
		{
			utime = 0;
			mtime = 0;
		}
		bool init(const string& path)
		{
			int len;
			File file;
			vector<string> vec;
			char content[4 * 1024];

			CHECK_FALSE_RETURN(file.open(path));
			
			len = file.read(content, sizeof(content) - 1);

			CHECK_FALSE_RETURN(len >= 0);
	
			content[len] = 0;

			stdx::split(vec, content, "\n");

			for (string& line : vec)
			{
				line = stdx::trim(line);

				if (line[0] == '#')
				{
					size_t pos = line.find('<');

					if (pos == string::npos) pos = line.find('\"');
					
					if (pos == string::npos) continue;

					line = stdx::trim(line.substr(pos), " <\">");
					line = path::name(line);

					incset.insert(stdx::tolower(line));
				}
			}

			this->mtime = this->utime = path::mtime(path);
			this->path = path;

			return true;
		}
		int update(map<string, time_t>& timemap)
		{
			int num = 0;

			for (const string& name : incset)
			{
				auto it = timemap.find(name);

				if (it == timemap.end()) continue;

				if (mtime < it->second)
				{
					mtime = it->second;
					num++;
				}
			}

			if (num > 0)
			{
				string name = path::name(path);
				
				timemap[stdx::tolower(name)] = mtime;
			}

			return num;
		}
	};

	map<string, time_t> timemap;
	vector<sp<FileItem>> filevec;

public:
	bool main()
	{
		string path;
		vector<string> vec;
		vector<string> taglist = {"*.h", "*.c", "*.cpp"};

		if (GetCmdParam(1)) path = stdx::trim(GetCmdParam(1));

		if (path.empty()) path = ".";

		for (string& tag : taglist)
		{
			stdx::FindFile(vec, path, tag);

			for (string& name : vec)
			{
				sp<FileItem> file = newsp<FileItem>();

				file->init(name);

				name = path::name(name);

				auto it = timemap.find(stdx::tolower(name));

				if (it == timemap.end())
				{
					timemap[name] = file->utime;
				}
				else
				{
					if (it->second < file->utime)
					{
						it->second = file->utime;
					}
				}

				filevec.push_back(file);
			}
		}

		while (true)
		{
			int num = 0;

			for (auto& file : filevec) num += file->update(timemap);

			if (num == 0) break;
		}

		for (auto& file : filevec)
		{
			if (file->mtime <= file->utime) continue;

			string name = path::extname(file->path);

			if (name == "c" || name == "cpp")
			{
				SetFileUpdateTime(file->path.c_str(), &file->mtime);
			}
		}

		return true;
	}
};

START_APP(UpdateApplication)